Skip to content

Add HTTP1Connection #400

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 13, 2021
Merged

Conversation

fabianfett
Copy link
Member

This PR adds an HTTP1Connection class that will be used in our new ConnectionPool.

This PR is under-tested as of right now, but I would love to get some early feedback on the current implementation.

@fabianfett fabianfett added the 🔨 semver/patch No public API change. label Jul 8, 2021
@fabianfett fabianfett added this to the HTTP/2 support milestone Jul 8, 2021
@fabianfett fabianfett force-pushed the ff-http1-connection branch 2 times, most recently from 6b4c5cf to 068235c Compare July 8, 2021 14:58
Comment on lines 94 to 96
func close(context: ChannelHandlerContext, mode: CloseMode, promise: EventLoopPromise<Void>?) {
context.close(mode: mode, promise: promise)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this meant to just be the default implementation?

self.logger.trace("New request to execute")

let req = self.unwrapOutboundIn(data)
self.request = req
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if there's already a request running?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will catch that in the state machine. But I guess it doesn't hurt to add another assert here!


// MARK: - Run Actions

func run(_ action: HTTP1ConnectionStateMachine.Action, context: ChannelHandlerContext) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: private

switch action {
case .sendRequestHead(let head, startBody: let startBody):
if startBody {
context.write(wrapOutboundOut(.head(head)), promise: nil)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: explicit self for wrapOutboundOut (and below)

}
}

private func clearIdleReadTimeoutTimer() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this ever called? Looks like it was superseded by resetIdleReadTimeoutTimer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added code that uses that :)


private func writeRequestBodyPart0(_ data: IOData, request: HTTPExecutingRequest) {
guard self.request === request else {
// very likely we got threading issues here...
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who would have gotten this wrong, us or the caller? Should we assert/precondition accordingly?

self.run(action, context: self.channelContext)
}

func cancelRequest0(_ request: HTTPExecutingRequest) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: private

final class HTTP1Connection {
let channel: Channel

/// the connection pool that created the connection
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a delegate rather than a pool. Presumably a pool most of the time though.

import NIOHTTP1
import XCTest

class HTTP1ClientChannelHandlerTests: XCTestCase {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume you'll add to this later.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some.

@fabianfett fabianfett force-pushed the ff-http1-connection branch from ad97a25 to c93cac7 Compare July 8, 2021 16:27
@fabianfett fabianfett force-pushed the ff-http1-connection branch from c93cac7 to 663aaae Compare July 9, 2021 10:44
@fabianfett fabianfett requested a review from glbrntt July 12, 2021 07:41
}

func read(context: ChannelHandlerContext) {
self.logger.trace("Read")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a plan to remove this log? If no, can we give it a better title?

init(connection: HTTP1Connection, eventLoop: EventLoop, logger: Logger) {
self.connection = connection
self.eventLoop = eventLoop
self.logger = logger
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the collection of basically anonymous logs emitted from this logger we absolutely must attach some metadata to it so we can filter them.

//
// This source file is part of the AsyncHTTPClient open source project
//
// Copyright (c) 2018-2019 Apple Inc. and the AsyncHTTPClient project authors
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the license field here?

@fabianfett fabianfett force-pushed the ff-http1-connection branch from 7579b95 to f7d2416 Compare July 13, 2021 09:59
Comment on lines +98 to +130
private func start(configuration: HTTPClient.Configuration, logger: Logger) throws {
self.channel.eventLoop.assertInEventLoop()

guard case .initialized = self.state else {
preconditionFailure("Connection must be initialized, to start it")
}

self.state = .active
self.channel.closeFuture.whenComplete { _ in
self.state = .closed
self.delegate.http1ConnectionClosed(self)
}

do {
let sync = self.channel.pipeline.syncOperations
try sync.addHTTPClientHandlers()

if case .enabled(let limit) = configuration.decompression {
let decompressHandler = NIOHTTPResponseDecompressor(limit: limit)
try sync.addHandler(decompressHandler)
}

let channelHandler = HTTP1ClientChannelHandler(
connection: self,
eventLoop: channel.eventLoop,
logger: logger
)

try sync.addHandler(channelHandler)
} catch {
self.channel.close(mode: .all, promise: nil)
throw error
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Lukasa dragged the stuff out!

@fabianfett fabianfett requested a review from Lukasa July 13, 2021 10:29
@fabianfett fabianfett merged commit e967f9a into swift-server:main Jul 13, 2021
@fabianfett fabianfett deleted the ff-http1-connection branch July 13, 2021 11:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🔨 semver/patch No public API change.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants